'''
Description: 文件接收器模块
Author: HowsenFisher
Date: 2021-04-07 22:29:35
LastEditTime: 2021-04-11 11:56:54
LastEditors: liutq
Reference: 
'''
import socket
import os
from threading import Thread
class FileReceiver:
    '''
    @description: 文件接收器类
    @param  {*}
    @return {*}
    @param {*} self
    @param {*} parent：父对象
    @param {*} ip：本机IP
    @param {*} port：文件接收端口
    @param {*} savePath：文件保存位置
    '''
    def __init__(self,parent,ip,port,savePath):
        # 父对象
        self.parent = parent
        # 打印info
        self.parent.newInfoSignal.emit("文件接收器初始化")
        # 文件接收端口
        self.port = port
        # 文件保存位置
        self.savePath = savePath
        # 建立TCP socket
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 绑定本机文件接收端口
        self.s.bind((ip,self.port))
        while True:
            # 打印info
            self.parent.newInfoSignal.emit("文件接收器绑定端口:%d"%self.port)
            # 等待队列最大值为255
            self.s.listen(255)
            # 接受一个对方的连接，拿到地址和发送方的socket对象
            sender,senderAddr = self.s.accept()
            # 打印info
            self.parent.newInfoSignal.emit("文件接收器检测到发送者地址:%s"%senderAddr[0])
            # 创建文件接收循环线程（每收到一个连接请求就创建一个线程）
            t = Thread(target=lambda:self.receiveLoop(sender,senderAddr))
            # 开启线程
            t.start()
    
    '''
    @description: 文件接收循环函数
    @param  {*}
    @return {*}
    @param {*} self
    @param {*} sender：发送方socket对象
    @param {*} senderAddr：发送方地址
    '''
    def receiveLoop(self,sender,senderAddr):
        while True:
            # 接收来自发送方的数据，接受长度10240
            res = self.receive(10240,sender,senderAddr)
            # 如果接收函数返回断开连接就打断循环
            if res=="disconnect":
                break

    '''
    @description: 接收文件函数
    @param  {*}
    @return {*}
    @param {*} self
    @param {*} length：接收长度
    @param {*} sender：发送方socket对象
    @param {*} senderAddr：发送方地址
    '''
    def receive(self,length,sender,senderAddr):
        # 打印info
        self.parent.newInfoSignal.emit("文件接收器://////开启一个新的文件接收///////")
        # 等待对方发送文件名
        filename = ""
        while True:
            # 接收数据
            data = sender.recv(length)
            # 如果接收的数据不为空且不是断开连接，就获取文件名
            if not data == b'' and not data==b'disconnect':
                filename = data.decode('utf-8')
                break
            # 如果收到了断开连接，就返回断开连接
            if data == b'disconnect':
                return 'disconnect'
        # 打印info
        self.parent.newInfoSignal.emit("文件名: %s"%filename)
        # 返回文件名接收成功
        sender.send("filename ok".encode("utf-8"))
        # 关闭文件夹监视
        # self.parent.FolderWatcherObj.stop()
        # 开始文件接收，先尝试删除已有文件（因为后续写入是追加方式）
        try:
            os.remove(self.savePath+"/"+filename)
        except OSError:
            pass
        # 创建文件
        myfile = open(self.savePath+"/"+filename,"ab")
        while True:
            # 尝试去接收消息，因为会碰到执行在此处恰好对方断开连接的情况
            data = b''
            try:
                # 接收数据
                data = sender.recv(length)
            # 若发生了连接中断错误，返回断开连接
            except ConnectionAbortedError:
                return 'disconnect'
            # 如果接收到了空串或者文件发送完毕则跳出接收循环
            if data==b'':
                break
            if data==b'file send finish!':
                break
            # 将接收到的bytes写入文件
            myfile.write(data)
            # 向发送方返回接收完毕的反馈
            sender.send("receive ok".encode("utf-8"))
        # 打印info
        self.parent.newInfoSignal.emit("文件接收器:文件接收完成!")
        # 文件关闭
        myfile.close()
        # 打开文件夹监视
        # self.parent.FolderWatcherObj.start()


if __name__ == "__main__":
    myFileReceiver = FileReceiver(ip="127.0.0.1",port=913,savePath="./")
    myFileReceiver.receive(10240)
        